<?php
/**
 * Created by PhpStorm.
 * User: wuxiansheng
 * Date: 2018/8/18
 * Time: 18:23
 */

namespace App\Console\Service\IPProxyPool\Process;

use App\Console\Service\IPProxyPool\Inc\config;
use App\Console\Service\IPProxyPool\Inc\Useragent;
use App\Console\Service\IPProxyPool\Uitl\IpLocation;
use App\Console\Service\IPProxyPool\Uitl\Monolog;
use Illuminate\Support\Facades\Redis;

class Validate
{

    private $iplocation;

    public function __construct()
    {
        $qqwry = dirname(dirname(__file__)) . "/lib/qqwry.dat";
        $this->iplocation = new IpLocation($qqwry);
    }

    /**
     * 多进程执行逻辑
     */
    public function run()
    {

        $logger = function (string $str) {
            Monolog::info('IPProxyPool----->>>>>>>>validate ' . $str);
        };

        $logger('Process - beginning');
        $t1 = microtime(true);

        //创建过程
        $worker_num = 30;
        $process_pool = [];
        $process = null;

        //创建worker进程
        for ($i = 0; $i < $worker_num; $i++) {
            $process = new \swoole_process(function (\swoole_process $worker) use ($logger) {
                $logger('worker:' . $worker->pid . ' start');
                while ($proxy = Redis::SPOP("index:types")) {
                    $this->checkProxy($worker, $proxy, $logger); //验证过程
                }
                $logger('worker:' . $worker->pid . ' exit');
            });
            $process->start();
            $pid = $process->pid;
            $process_pool[$pid] = $process;
        }

        //子进程结束必须要执行wait进行回收，否则子进程会变成僵尸进程
        while ($ret = \swoole_process::wait()) {// $ret 是个数组 code是进程退出状态码，
            $logger("worker Exit, PID=" . $ret['pid'] . " CODE=" . $ret['code']);
        }
        $logger("Master exit");
        $logger('耗时' . round(microtime(true) - $t1, 3) . '秒');

    }

    /**
     * 验证过程
     * @param \swoole_process $worker
     * @param $proxy
     * @param $logger
     */
    private function checkProxy(\swoole_process $worker, $proxy, $logger)
    {

        $proxyIp = explode(":", $proxy);
        $http = config::$test_http_header;
        $https = config::$test_https_header;
        $httpProxy = "http://" . $proxyIp[1] . ":" . $proxyIp[2];
        $httpsProxy = "https://" . $proxyIp[1] . ":" . $proxyIp[2];

        $httpResponse = $this->curl($http, $httpProxy);
        $httpsResponse = $this->curl($https, $httpsProxy);

        $location = $this->iplocation->getlocation($httpResponse[0]);
        try{
            $location['country'] = iconv('GB2312', 'UTF-8', $location['country']);
            $location['area'] = iconv('GB2312', 'UTF-8', $location['area']);
        }catch (Exception $e){

        }

        if (!empty($httpResponse[0])) {
            try {
                $response = json_decode($httpResponse[0], true);
                Redis::SADD("index:types:success", $httpProxy);
                Redis::ZADD('index:types:http', $httpResponse[2], $httpProxy);
                $logger('worker:' . $worker->pid . " http success");
            } catch (Exception $e) {
                $logger('worker:' . $worker->pid . " http json error");
            }
        } else {
            $logger('worker:' . $worker->pid . " http error");
        }

        if (!empty($httpsResponse[0])) {
            try {
                $response = json_decode($httpsResponse[0], true);
                Redis::SADD("index:types:success", $httpsProxy);
                Redis::ZADD('index:types:https', $httpResponse[2], $httpProxy);
                $logger('worker:' . $worker->pid . " https success");
            } catch (Exception $e) {
                $logger('worker:' . $worker->pid . " https json error");
            }
        } else {
            $logger('worker:' . $worker->pid . " https error");
        }

    }

    /**
     * 添加代理IP验证
     * @param $url
     * @param $proxy
     * @return array
     */
    private function curl($url, $proxy)
    {
        $t1 = microtime(true);
        $user_agent = Useragent::pull();
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_PROXY, $proxy);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_USERAGENT, $user_agent);
        curl_setopt($ch, CURLOPT_HEADER, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        $result = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        $t2 = microtime(true);
        $runTime = round($t2 - $t1, 5);
        return array($httpCode, $result, $runTime);
    }

}